/*
 * Description:guest对外服务服务端实现类
 */
#include "recvfrom_host.h"
#include "log.h"
#include "error.h"
#include "connect_common.h"
#include "../common/guest_utils.h"
#include "../common/text_utils.h"
#include "../common/session_utils.h"
#include "../common/win_update_utils.h"
#include "host2guest.pb.h"
#include "shellapi.h"
#include "objbase.h"
#include <CString>
#include <tchar.h>
#include "sstream"
#include "regex"
#include "../app_filter/app_filter_manager.h"
#include "../share_folder/share_folder_helper.h"
#include "../process_load_statistic/sys_cpu_calc.h"
#include "../power_consumption/application_monitor.h"
#include "../performance/perf_manager.h"
#include "../performance/process_monitor_injector.h"
#include "../performance/utils/registry_utils_ex.h"
#include "../performance/utils/perf_utils.h"
#include "../performance/perf_event_dispatcher.h"
#include "../dfx/process_detect.h"
#include "guest_manager.h"
#include "../dfx/stability/event_reporter.h"
#include "../dfx/driver_report.h"
#include "../common/path_utils.h"
#ifdef _FUZZ
#include "GuestLinkFuzzWindowsServer.h"
#endif

using namespace COMMON;
using namespace Guest::protobuf;
using namespace std;
using PERF::RegistryUtilsEx;

namespace {
    const string LOCAL_DRIVER_BAT_PATH = "C:\\ProgramData\\VMAgent\\DriverUpdate.bat";
    const string LOCAL_AGENT_BAT_PATH = "C:\\ProgramData\\VMAgent\\VMAgentUpdate.bat";
    const string APPLICATION_WINDOW_BAT_PATH = "C:\\ProgramData\\VMAgent\\ApplicationWindowUpdate.bat";
    const string PRE_WNDCONTROL_BAT_PATH = "C:\\ProgramData\\VMAgent\\PreControlUpdate.bat";
    const string PS_HIDE_WINDOW_BAT_PATH = "C:\\ProgramData\\VMAgent\\PsHideWindowUpdate.bat";
    const string PS_CONTROL_BAT_PATH = "C:\\ProgramData\\VMAgent\\PsControlUpdate.bat";
    const string DISPALY_BAT_PATH = "C:\\ProgramData\\VMAgent\\DisplayUpdate.bat";
    const string SVGA_ADAPTER_BAT_PATH = "C:\\ProgramData\\VMAgent\\SvgaAdapterUpdate.bat";
    const string PERF_PSMON_UPDATE_BAT_PATH = "C:\\ProgramData\\VMAgent\\PsMonUpdate.bat";
    const string PERF_INSTALL_CONF_UPDATE_PATH = "C:\\ProgramData\\VMAgent\\InstallConfUpdate.bat";
    const string PERF_WNDFETCH_UPDATE_BAT_PATH = "C:\\ProgramData\\VMAgent\\WndFetchUpdate.bat";
    const string PERF_VISUAL_EFFECTS_EDIT_UPDATE_BAT_PATH = "C:\\ProgramData\\VMAgent\\VisualEffectsEditUpdate.bat";
    const string PERF_PRELOAD_HELPER_UPDATE_BAT_PATH = "C:\\ProgramData\\VMAgent\\PerloadHelperUpdate.bat";
    const string PERF_CONFIG_UPDATE_BAT_PATH = "C:\\ProgramData\\VMAgent\\PerfCfgUpdate.bat";
    const string APP_FILTER_UPDATE_BAT_PATH = "C:\\ProgramData\\VMAgent\\AppFilterUpdate.bat";
    const string WDDM_UPDATE_BAT_PATH = "C:\\ProgramData\\VMAgent\\wddmUpdate.bat";
    const string CONFIG_UPDATE_BAT_PATH = "C:\\ProgramData\\VMAgent\\ConfigUpdate.bat";
    const string WIN_EVT_MONITOR_UPDATE_BAT_PATH = "C:\\ProgramData\\VMAgent\\WinEvtMonitorUpdate.bat";
    const string GET_DRIVER_AGENT_PATH = "C:\\ProgramData\\VMAgent\\GetFile.bat";
    const string UPDATE_CONFIRM_PATH = "C:\\ProgramData\\VMAgent\\UpdateBar.bat";
    const string DRIVER_DELETE_REPEAT_PATH = "C:\\ProgramData\\VMAgent\\removeRepeatDriver.bat";
    const string AUTO_PAUSE_CONFIG_UPDATE_PATH = "C:\\ProgramData\\VMAgent\\AutoPauseConfigUpdate.bat";
    const string TEMP_DIR = "C:\\ProgramData\\VMAgent\\UpdateTemp\\";
    const string CURR_DIR = "C:\\ProgramData\\";
    const string DFX_SHARE_NAME = "dfx_folder";
    const int SHELL_EXECUTE_FAIL = 32;
    const int TIME_ARGUMENT_COUNT = 6;
    const int POLLING_TIME = 1000;
    const int POLLING_COUNT = 10;
    bool DRIVER_UPDATING = false;
    bool WDDM_UPDATE = false;
    const std::string TOUCH_KEYBOARD_REG_SUBKEY_PATH =
        R"(\Software\Microsoft\TabletTip\1.7)";

    const std::vector<std::string> DRIVER_UPDATE_CMD = {
        "@echo off",
        "echo %date% %time%",
        "%PROGRAMDATA%\\VMAgent\\driver1\\viogpu\\vmgtsrv.exe -u",
        "cd %PROGRAMDATA%\\VMAgent",
        "if exist wddm rmdir wddm /s /q",
        "move /Y driver1\\wddm .",
        "icacls * /grant Administrators:(OI)(CI)F /T",
        "tar -xf C:\\ProgramData\\VMAgent\\UpdateTemp\\driver.zip -C %PROGRAMDATA%\\VMAgent\\",
        "cd %PROGRAMDATA%\\VMAgent\\driver0",
        "pnputil /add-driver *.inf /subdirs /install",
        "cd %PROGRAMDATA%\\VMAgent\\driver1",
        "move /Y wddm ..\\UpdateTemp",
        "pnputil /add-driver *.inf /subdirs /install",
        "%PROGRAMDATA%\\VMAgent\\driver1\\viogpu\\vmgtsrv.exe -i",
        "cd %PROGRAMDATA%\\VMAgent\\driver2\\balloon",
        "pnputil /add-driver balloon.inf /install",
        "cd %PROGRAMDATA%\\VMAgent\\driver2",
        "scream\\helpers\\devcon-arm64.exe disable *Scream",
        "pnputil /add-driver ivshmem\\ivshmem.inf /install",
        "scream\\helpers\\devcon-arm64.exe enable *Scream",
        "scream\\helpers\\devcon-arm64.exe remove *Scream",
        "scream\\helpers\\devcon-arm64.exe install scream\\driver\\arm64\\Scream.inf *Scream",
        "hwfs\\devcon-arm64.exe remove \"root\\hwfs\"",
        "hwfs\\devcon-arm64.exe install hwfs\\hwfs\\hwfs.inf \"root\\hwfs\"",
        "rundll32.exe hwfs\\hwfs\\hwfs_np.dll,HWFSInstall",
        "cd %PROGRAMDATA%\\VMAgent\\driver2\\app_filter",
        "devcon-arm64.exe remove \"root\\app_filter_driver\"",
        "devcon-arm64.exe install app_filter_driver\\app_filter_driver.inf \"root\\app_filter_driver\"",
        "cd %PROGRAMDATA%\\VMAgent",
        "move /Y wddm driver1",
        "del %0",
    };

    const std::vector<std::string> WDDM_UPDATE_CMD = {
        "@echo off",
        "echo %date% %time%",
        "move /Y C:\\ProgramData\\VMAgent\\UpdateTemp\\wddm C:\\ProgramData\\VMAgent",
        "cd %PROGRAMDATA%\\VMAgent\\wddm",
        "pnputil /add-driver svgampwddm.inf /install",
        "rmdir /s /q C:\\ProgramData\\VMAgent\\driver1\\wddm",
        "move /Y C:\\ProgramData\\VMAgent\\UpdateTemp\\driver.zip C:\\ProgramData\\VMAgent",
        "del %0",
    };

    const std::vector<std::string> DRIVER_DELETE_REPEAT = {
        "@echo off",
        "echo %date% %time%",
        "setlocal enabledelayedexpansion",
        "pnputil /enum-drivers |findstr /n \"^\" > pnputil.txt",
        "set \"array=balloon.inf hwfs.inf app_filter_driver.inf ivshmem.inf pvpanic-pci.inf vioser.inf viostor.inf"
        " netkvm.inf scream.inf viogpudo.inf vioinput.inf viofs.inf svgampwddm.inf\"",
        "for %%i in (%array%) do ("
        "echo \"%%i\"",
        "for /f \"delims=:\" %%a in ('findstr /c:\" %%i\" pnputil.txt') do (",
        "set /a line=%%a-1",
        "set /a line_date=%%a+4",
        "for /f \"tokens=3 delims=:\" %%a in ('findstr /b \"!line!:\" pnputil.txt')"
        " do for %%b in (%%a) do set \"oem=%%b\"",
        "echo \"!oem!\"",
        "for /f \"tokens=2\" %%d in ('findstr /b \"!line_date!:\" pnputil.txt') do (",
        "set \"tmp=%%d\"",
        "echo \"!tmp!\"",
        "set \"tmpDate=!tmp:~6,4!!tmp:~0,2!!tmp:~3,2!\"",
        "echo \"!tmpDate!\"",
        "if !tmpDate! GTR !latestDate! (",
        "if defined latestOem pnputil /delete-driver !latestOem! /uninstall",
        "set \"latestDate=!tmpDate!\" ",
        "set \"latestOem=!oem!\"",
        ") else pnputil /delete-driver !oem! /uninstall",
        ")",
        ")",
        "set \"latestDate=\"",
        "set \"latestOem=\"",
        ")",
        "del pnputil.txt",
        "endlocal",
        "del %0",
    };

    const std::vector<std::string> VMAGENT_UPDATE_CMD = {
        "echo %date% %time%",
        "net stop vmagent",
        "set /a retry =10",
        ":checkend",
        "tasklist|find /i \"agent_service.exe\"",
        "if %errorlevel% gtr 0 (goto update) else (", // 即VMAgent进程还在
        "taskkill /F /IM agent_service.exe",
        "if %retry% equ 0 goto end", // 重试次数未超出
        "timeout /t 1",
        "set /a retry = retry -1",
        "goto checkend)",
        ":update",
        "cd %PROGRAMDATA%\\VMAgent",
        "move /Y agent_service1.exe agent_service.exe",
        "net start vmagent",
        "tasklist|find /i \"agent_service.exe\"",
        "if %errorlevel% gtr 0 (net start vmagent) ",
        ":end",
        "del %0",
    };

    const std::vector<std::string> GET_DRIVER_AGENT_FILE = {
        "@echo off",
        "echo %date% %time%",
        "if not exist C:\\ProgramData\\VMAgent\\UpdateTemp mkdir C:\\ProgramData\\VMAgent\\UpdateTemp",
        "del /Q C:\\ProgramData\\VMAgent\\UpdateTemp\\*",
        "if exist C:\\ProgramData\\VMAgent\\UpdateTemp\\wddm rmdir C:\\ProgramData\\VMAgent\\UpdateTemp\\wddm /s /q",
        "FOR %%I IN (A D E F G H I J K L N M O P Q R S T U V W X Y Z) DO IF EXIST %%I:\\driver\\driver.zip "
        "IF EXIST %%I:\\agent_service.exe (COPY %%I:\\driver\\driver.zip %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\agent_service.exe %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\win_evt_monitor\\win_evt_monitor.exe %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\config\\PerfSoftwareList.json %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\performance\\application_window_helper.exe %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\performance\\pre_process_wndcontrol.exe %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\performance\\ps_hide_window.dll %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\performance\\ps_process_control.exe %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\performance\\wndtext_fetch_helper.exe %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\performance\\VisualEffectsEdit.exe %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\performance\\process_monitor.dll %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\performance\\perf.cfg %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\display\\display.exe %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\display\\svga_adapter.dll %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\app_filter\\FilterAgent.exe %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\app_filter\\config.json %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\performance\\PreloadHelper.exe %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\config\\InstallationList.json %PROGRAMDATA%\\VMAgent\\UpdateTemp "
        "&& COPY %%I:\\config\\AutoPauseList.json %PROGRAMDATA%\\VMAgent\\UpdateTemp)",
        "cd %PROGRAMDATA%\\VMAgent",
        "timeout /t 1",
        "del %0"
    };
    const std::vector<std::string> APPLICATION_WINDOW_HELPER_UPDATE_CMD = {
        "echo %date% %time%",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\application_window_helper.exe %PROGRAMDATA%\\performance\\",
        "del %0"
    };
    const std::vector<std::string> PRE_PROCESS_WNDCONTROL_UPDATE_CMD = {
        "echo %date% %time%",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\pre_process_wndcontrol.exe %PROGRAMDATA%\\performance\\",
        "del %0"
    };
    const std::vector<std::string> PS_HIDE_WINDOW_UPDATE_CMD = {
        "echo %date% %time%",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\ps_hide_window.dll %PROGRAMDATA%\\performance\\",
        "del %0"
    };
    const std::vector<std::string> PS_PROCESS_CONTROL_UPDATE_CMD = {
        "echo %date% %time%",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\ps_process_control.exe %PROGRAMDATA%\\performance\\",
        "del %0"
    };
    const std::vector<std::string> PERF_PSMON_UPDATE_CMDS = {
        "echo %date% %time%",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\process_monitor.dll %PROGRAMDATA%\\performance\\",
        "del %0"
    };
    const std::vector<std::string> PERF_INSTALL_CONF_UPDATE_CMDS = {
        "echo %date% %time%",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\installationList.json %PROGRAMDATA%\\vmagent\\config\\",
        "del %0"
    };
    const std::vector<std::string> PERF_WNDFETCH_UPDATE_CMDS = {
        "echo %date% %time%",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\wndtext_fetch_helper.exe %PROGRAMDATA%\\performance\\",
        "del %0"
    };

    const std::vector<std::string> PERF_VISUAL_EFFECTS_EDIT_UPDATE_CMDS = {
        "echo %date% %time%",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\VisualEffectsEdit.exe %PROGRAMDATA%\\performance\\",
        "del %0"
    };

    const std::vector<std::string> PERF_PRELOAD_HELPER_UPDATE_CMDS = {
        "echo %date% %time%",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\PreloadHelper.exe %PROGRAMDATA%\\performance\\",
        "del %0"
    };

    const std::vector<std::string> PERF_CONFIG_UPDATE_CMDS = {
        "echo %date% %time%",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\perf.cfg %PROGRAMDATA%\\performance\\",
        "del %0"
    };

    const std::vector<std::string> DISPLAY_UPDATE_CMD = {
        "echo %date% %time%",
        "move /y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\display.exe %PROGRAMDATA%\\display\\",
        "del %0"
    };
    const std::vector<std::string> SVGA_ADAPTER_UPDATE_CMD = {
        "echo %date% %time%",
        "move /y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\svga_adapter.dll %PROGRAMDATA%\\display\\",
        "del %0"
    };
    const std::vector<std::string> CONFIG_UPDATE_CMD = {
        "echo %date% %time%",
        "if not exist C:\\ProgramData\\VMAgent\\config mkdir C:\\ProgramData\\VMAgent\\config",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\PerfSoftwareList.json %PROGRAMDATA%\\VMAgent\\config",
        "del %0"
    };
    const std::vector<std::string> APP_FILTER_UPDATE_CMD = {
        "echo %date% %time%",
        "if not exist C:\\ProgramData\\AppFilter mkdir C:\\ProgramData\\AppFilter",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\FilterAgent.exe %PROGRAMDATA%\\AppFilter",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\config.json %PROGRAMDATA%\\AppFilter",
        "del %0"
    };
    const std::vector<std::string> WIN_EVT_MONITOR_UPDATE_CMD = {
        "echo %date% %time%",
        "taskkill /F /IM win_evt_monitor.exe",
        "if not exist C:\\ProgramData\\WinEvtMonitor mkdir C:\\ProgramData\\WinEvtMonitor",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\win_evt_monitor.exe %PROGRAMDATA%\\WinEvtMonitor\\",
        "del %0",
    };

    const std::vector<std::string> UPDATE_CONFIRM_BAT = {
        "@echo off",
        "echo %date% %time% UPDATE_CONFIRM_BAT",
        "if not exist %PROGRAMDATA%\\VMAgent\\update mkdir %PROGRAMDATA%\\VMAgent\\update",
        "FOR %%I IN (A D E F G H I J K L N M O P Q R S T U V W X Y Z) DO IF EXIST %%I:\\update\\update_bar.exe "
        "(COPY %%I:\\update\\update_bar.exe %PROGRAMDATA%\\VMAgent\\ "
        "&& COPY %%I:\\update\\update_confirm.exe %PROGRAMDATA%\\VMAgent\\ "
        "&& COPY %%I:\\update\\update_confirm.exe %PROGRAMDATA%\\VMAgent\\update\\)",
        "timeout /t 1",
        "del %0"
    };

    const std::vector<std::string> AUTO_PAUSE_CONFIG_UPDATE_CMDS = {
        "echo %date% %time%",
        "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\AutoPauseList.json %PROGRAMDATA%\\VMAgent\\config\\",
        "del %0"
    };

    const std::map<std::string, std::vector<std::string>> cmdMap = {
        {"Driver", DRIVER_UPDATE_CMD},
        {"VMAgent", VMAGENT_UPDATE_CMD},
        {"ApplicationWindowHelper", APPLICATION_WINDOW_HELPER_UPDATE_CMD},
        {"PreProcessWndcontrol", PRE_PROCESS_WNDCONTROL_UPDATE_CMD},
        {"PsHideWindow", PS_HIDE_WINDOW_UPDATE_CMD},
        {"PsProcessControl", PS_PROCESS_CONTROL_UPDATE_CMD},
        {"PsMon", PERF_PSMON_UPDATE_CMDS},
        {"InstallConf", PERF_INSTALL_CONF_UPDATE_CMDS},
        {"WndFetch", PERF_WNDFETCH_UPDATE_CMDS},
        {"VisualEffectsEdit", PERF_VISUAL_EFFECTS_EDIT_UPDATE_CMDS},
        {"PreloadHelper", PERF_PRELOAD_HELPER_UPDATE_CMDS},
        {"PerfCfg", PERF_CONFIG_UPDATE_CMDS},
        {"Display", DISPLAY_UPDATE_CMD},
        {"SVGA_ADAPTER", SVGA_ADAPTER_UPDATE_CMD},
        {"wddm", WDDM_UPDATE_CMD},
        {"Config", CONFIG_UPDATE_CMD},
        {"WinEvtMonitor", WIN_EVT_MONITOR_UPDATE_CMD},
        {"AppFilter", APP_FILTER_UPDATE_CMD},
        {"AutoPauseConfig", AUTO_PAUSE_CONFIG_UPDATE_CMDS},
    };

    const std::map<std::string, std::string> batPathMap = {
        {"Driver", LOCAL_DRIVER_BAT_PATH},
        {"VMAgent", LOCAL_AGENT_BAT_PATH},
        {"ApplicationWindowHelper", APPLICATION_WINDOW_BAT_PATH},
        {"PreProcessWndcontrol", PRE_WNDCONTROL_BAT_PATH},
        {"PsHideWindow", PS_HIDE_WINDOW_BAT_PATH},
        {"PsProcessControl", PS_CONTROL_BAT_PATH},
        {"PsMon", PERF_PSMON_UPDATE_BAT_PATH},
        {"InstallConf", PERF_INSTALL_CONF_UPDATE_PATH},
        {"WndFetch", PERF_WNDFETCH_UPDATE_BAT_PATH},
        {"VisualEffectsEdit", PERF_VISUAL_EFFECTS_EDIT_UPDATE_BAT_PATH},
        {"PreloadHelper", PERF_PRELOAD_HELPER_UPDATE_BAT_PATH},
        {"PerfCfg", PERF_CONFIG_UPDATE_BAT_PATH},
        {"Display", DISPALY_BAT_PATH},
        {"SVGA_ADAPTER", SVGA_ADAPTER_BAT_PATH},
        {"wddm", WDDM_UPDATE_BAT_PATH},
        {"Config", CONFIG_UPDATE_BAT_PATH},
        {"WinEvtMonitor", WIN_EVT_MONITOR_UPDATE_BAT_PATH},
        {"AppFilter", APP_FILTER_UPDATE_BAT_PATH},
        {"AutoPauseConfig", AUTO_PAUSE_CONFIG_UPDATE_PATH},
    };
}

namespace GUEST {
using MsgFun = void(*)(RecvFromHost&, link::Call&, link::Result&);

void HandleShutdown(RecvFromHost &service, link::Call &call, link::Result &res);
void HandleForceShutdown(RecvFromHost &service, link::Call &call, link::Result &res);
void HandleRestart(RecvFromHost &service, link::Call &call, link::Result &res);
void HandleUpdate(RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res);
void HandleNetConfig(RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res);
void HandleCorrectTime(RecvFromHost &service, Guest::protobuf::link::Call &call,
    Guest::protobuf::link::Result &res);
void HandleSetOsType(RecvFromHost &service, Guest::protobuf::link::Call &call,
    Guest::protobuf::link::Result &res);
void HandleMountSharedFolder(RecvFromHost &service, Guest::protobuf::link::Call &call,
    Guest::protobuf::link::Result &res);
void HandleUnmountSharedFolder(RecvFromHost &service, Guest::protobuf::link::Call &call,
    Guest::protobuf::link::Result &res);
void HandleEnable2D(RecvFromHost &service, Guest::protobuf::link::Call &call,
    Guest::protobuf::link::Result &res);
void HandleModifyResolution(RecvFromHost &service, Guest::protobuf::link::Call &call,
    Guest::protobuf::link::Result &res);
void HandleGetAvailableLetterCount(RecvFromHost &service, Guest::protobuf::link::Call &call,
    Guest::protobuf::link::Result &res);
void HandleLock(RecvFromHost &service, link::Call &call, link::Result &res);
void HandleShareFolderServiceIsReady(RecvFromHost &service, link::Call &call, link::Result &res);
void HandleCopyAndPasteActionStatus(RecvFromHost& service, Guest::protobuf::link::Call& call,
    Guest::protobuf::link::Result& res);
void HandleCompressDecompressActionStatus(RecvFromHost& service, Guest::protobuf::link::Call& call,
    Guest::protobuf::link::Result& res);
void HandleApplicationWindowStatus(RecvFromHost& service, Guest::protobuf::link::Call& call,
    Guest::protobuf::link::Result& res);
void HandleIsWinLogon(RecvFromHost& service, Guest::protobuf::link::Call& call,
    Guest::protobuf::link::Result& res);
void HandleNotifyUpToDate(RecvFromHost& service, Guest::protobuf::link::Call& call,
    Guest::protobuf::link::Result& res);
void HandleSetTouchKeyboardVisibility(RecvFromHost& service, Guest::protobuf::link::Call& call,
    Guest::protobuf::link::Result& res);
void HandleQuickShutdown(RecvFromHost &service, link::Call &call, link::Result &res);
void HandleSyncHostDomainAccountAndSN(RecvFromHost &service, link::Call &call, link::Result &res);
void HandleSetAutoSyncDnsEnabled(RecvFromHost &service, link::Call &call, link::Result &res);
void HandleSyncProxy(RecvFromHost &service, link::Call &call, link::Result &res);
void HandleSyncDNS(RecvFromHost &service, link::Call &call, link::Result &res);
void HandleCheckWinUpdate(RecvFromHost &service, link::Call &call, link::Result &res);
void HandleServiceAlive(RecvFromHost& service, link::Call& call, link::Result& res);
void HandleTriggerVmUpdate(RecvFromHost &service, link::Call &call, link::Result &res);
void HandleInstallConfig(RecvFromHost &service, link::Call &call, link::Result &res);
#ifdef _FUZZ
void HandleStartFuzz(RecvFromHost &service, link::Call &call, link::Result &res);
#endif


const std::unordered_map<OPCode, MsgFun> HANDLE_MSG_ENTRY = {
    {OPCode::SHUTDOWN, &HandleShutdown},
    {OPCode::FORCESHUTDOWN, &HandleForceShutdown},
    {OPCode::NETCONFIG, &HandleNetConfig},
    {OPCode::UPDATAFILE, &HandleUpdate},
    {OPCode::CORRECTTIME, &HandleCorrectTime},
    {OPCode::SETOSTYPE, &HandleSetOsType},
    {OPCode::MOUNT_SHARED_FOLDER, &HandleMountSharedFolder},
    {OPCode::UNMOUNT_SHARED_FOLDER, &HandleUnmountSharedFolder},
    {OPCode::ENABLE_2D, &HandleEnable2D},
    {OPCode::GET_AVAILABLE_LETTER_COUNT, &HandleGetAvailableLetterCount},
    {OPCode::LOCK, &HandleLock},
    {OPCode::SHARE_FOLDER_SERVICE_IS_READY, &HandleShareFolderServiceIsReady},
    {OPCode::COPY_PASTE_FILE_STATUS, &HandleCopyAndPasteActionStatus},
    {OPCode::COMPRESS_DECOMPRESS_STATUS, &HandleCompressDecompressActionStatus},
    {OPCode::IS_APPLICATION_WINDOW_OPENED, &HandleApplicationWindowStatus},
    {OPCode::IS_WIN_LOGON, &HandleIsWinLogon},
    {OPCode::NOTIFY_UP_TO_DATE, &HandleNotifyUpToDate},
    {OPCode::MODIFY_RESOLUTION, &HandleModifyResolution},
    {OPCode::SET_TOUCH_KEYBOARD_VISIBILITY, &HandleSetTouchKeyboardVisibility},
    {OPCode::QUICKSHUTDOWN, &HandleQuickShutdown},
    {OPCode::SYNC_IDENTITY_INFO, &HandleSyncHostDomainAccountAndSN},
    {OPCode::SET_SYNC_DNS_ENABLED, &HandleSetAutoSyncDnsEnabled},
    {OPCode::SYNC_PROXY, &HandleSyncProxy},
    {OPCode::SYNC_DNS, &HandleSyncDNS},
    {OPCode::CHECK_WINUPDATE, &HandleCheckWinUpdate},
    {OPCode::SERVICE_ALIVE, &HandleServiceAlive},
    {OPCode::TRIGGER_UPDATE, &HandleTriggerVmUpdate},
    {OPCode::INSTALL_CONFIG, &HandleInstallConfig},
#ifdef _FUZZ
    {OPCode::STARTFUZZ, &HandleStartFuzz},
#endif
};

int RecvFromHost::InitService()
{
    LOG_INFO("Init guest service");
    int port = 1;
    int ret = EstablishEventServer(port);
    if (ret != OK) {
        LOG_ERR("EstablishEventServer failed serial port = {}", port);
    }

    return ret;
}

int RecvFromHost::DeInitService()
{
    LOG_INFO("deInit guest service");
    int ret = CloseEventServer();
    if (ret != OK) {
        LOG_ERR("CloseEventChannel failed!");
    }
    return ret;
}

void RecvFromHost::Dispatch(Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
#ifdef _FUZZ
    if (this->isFuzzMode) {
        LOG_INFO("recv fuzz msg");
        TEST::GuestLinkFuzzWindowsServer::HandleMsg();
        return;
    }
#endif
    auto it = HANDLE_MSG_ENTRY.find(static_cast<OPCode>(call.methodid()));
    if (it != HANDLE_MSG_ENTRY.end()) {
        it->second(*this, call, res);
    } else {
        LOG_ERR("invalid op code: {}", call.methodid());
    }
}

void HandleShutdown(RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    LOG_INFO("Shutdown guest");
    std::string shutdownCmd = "shutdown /s /hybrid /t 0";
    if (!GuestUtils::ExecCmd(shutdownCmd, true)) {
        LOG_ERR("Failed to execute {}", shutdownCmd);
    }
}

void HandleForceShutdown(RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    LOG_INFO("ForceShutdown guest");
    Guest::protobuf::GuestAgent::Bool parameters;
    service.ParseProto(parameters, call);
    bool powerDown = parameters.value();
    WinUpdateUtils::DelayUpdate();
    std::string shutdownCmd = "shutdown -s -t 0 -f";
    if (!GuestUtils::ExecCmd(shutdownCmd, false, false)) {
        LOG_ERR("Failed to execute {}", shutdownCmd);
    }
    if (powerDown) {
        LOG_INFO("will automatic excute NtShutdownSystem.");
        service.SetForceShutdownState(true);
    }
}

void RecvFromHost::QuickShutdown()
{
    LOG_INFO("QuickShutdown guest");

    // 定义SE_SHUTDOWN_PRIVILEGE的值
    const ULONG SE_SHUTDOWN_PRIVILEGE = 0x13;

    // 声明RtlAdjustPrivilege和NtShutdownSystem函数类型
    typedef NTSTATUS(NTAPI* PFN_RtlAdjustPrivilege)(ULONG, BOOLEAN, BOOLEAN, PBOOLEAN);
    typedef NTSTATUS(NTAPI* PFN_NtShutdownSystem)(ULONG);

    HMODULE hNtdll = LoadLibraryW(L"ntdll.dll");
    if (hNtdll) {
       // 获取RtlAdjustPrivilege函数指针
       PFN_RtlAdjustPrivilege RtlAdjustPrivilege = (PFN_RtlAdjustPrivilege)GetProcAddress(hNtdll, "RtlAdjustPrivilege");
       // 获取NtShutdownSystem函数指针
       PFN_NtShutdownSystem NtShutdownSystem = (PFN_NtShutdownSystem)GetProcAddress(hNtdll, "NtShutdownSystem");

       if (RtlAdjustPrivilege && NtShutdownSystem) {
           BOOLEAN wasEnabled = FALSE;
           // 提升SE_SHUTDOWN_NAME权限
           NTSTATUS status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &wasEnabled);
           if (status == 0) {
               // 执行关机操作
               NtShutdownSystem(0); // 0代表关机且不重启
           } else {
               LOG_ERR("Failed to adjust privilege.");
           }
       } else {
           LOG_ERR("Failed to get function pointers.");
       }
       FreeLibrary(hNtdll);
    } else {
        LOG_ERR("Failed to load ntdll.dll.");
    }
}

void HandleQuickShutdown(RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    std::map<std::string, std::string> eventData = {
        {CALL_TYPE, "1"}
    };
    EVENT_REPORTER.ReportEventData(SA_VM_QUICK_SHUTDOWN, eventData);
    service.QuickShutdown();
}

void HandleLock(RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    LOG_INFO("Lock guest");
    SessionUtils::Lock();
}

void HandleEnable2D(RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    LOG_INFO("enable 2d");
    Guest::protobuf::GuestAgent::ResolutionInfo parameters;
    service.ParseProto(parameters, call);
    uint32_t surfaceWidth = parameters.surfacewidth();
    uint32_t surfaceHeight = parameters.surfaceheight();
    if (SessionUtils::IsUserLogon()) {
        GuestUtils::InitDisplay(surfaceWidth, surfaceHeight);
    } else {
        // 注册回调 每次登陆执行
        SessionUtils::RegLogonCallback(std::bind(GuestUtils::InitDisplay, surfaceWidth, surfaceHeight));
    }
}

void HandleModifyResolution(RecvFromHost &service, Guest::protobuf::link::Call &call,
    Guest::protobuf::link::Result &res)
{
    LOG_INFO("modify resolution");
    Guest::protobuf::GuestAgent::ResolutionInfo parameters;
    service.ParseProto(parameters, call);
    uint32_t surfaceWidth = parameters.surfacewidth();
    uint32_t surfaceHeight = parameters.surfaceheight();
    bool isInstall = parameters.isinstall();
    bool modifyResult = false;
    modifyResult = service.ModifyResolution(service, surfaceWidth, surfaceHeight, isInstall);
    LOG_INFO("Modify resolution result:{}", modifyResult);
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value(modifyResult);
    COMMON::LinkBase::SerializeAndResponse(result, res);
}

bool RecvFromHost::ModifyResolution(RecvFromHost &service, const uint32_t surfaceWidth, const uint32_t surfaceHeight,
                                    const bool isInstall)
{
    int count = 0;
    while (!SessionUtils::IsUserLogon() && count < POLLING_COUNT) {
        LOG_WARN("User not logon, wait a little while");
        Sleep(POLLING_TIME);
        count++;
    }
    return GuestUtils::ModifyResolution(surfaceWidth, surfaceHeight, isInstall);
}

void HandleNetConfig(RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    LOG_INFO("NetConfig");
    Guest::protobuf::GuestAgent::NetInfo parameters;
    service.ParseProto(parameters, call);
    bool configResult = service.NetConfig(parameters.ipaddr(), parameters.gatewayip());
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value(configResult);
    COMMON::LinkBase::SerializeAndResponse(result, res);
}

void HandleCorrectTime(RecvFromHost &service, Guest::protobuf::link::Call &call,
    Guest::protobuf::link::Result &res)
{
    LOG_INFO("CorrectTime and CorrectTimeZone");
    Guest::protobuf::GuestAgent::TimeInfo parameters;
    service.ParseProto(parameters, call);
    bool setTimeResult = service.CorrectTime(parameters.hosttime(), parameters.timezoneoffset());
}

void HandleSetOsType(RecvFromHost &service, Guest::protobuf::link::Call &call,
    Guest::protobuf::link::Result &res)
{
    LOG_INFO("SetOsType");
    Guest::protobuf::GuestAgent::String parameters;
    service.ParseProto(parameters, call);
    std::string osType = parameters.value();
    LOG_INFO("Get OsType :{}", osType);
    service.SetOsType(osType);
}

void HandleMountSharedFolder(
    RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    Guest::protobuf::GuestAgent::String parameters;
    service.ParseProto(parameters, call);
    std::string shareName = parameters.value();
    if (shareName == DFX_SHARE_NAME) {
        return;
    }
    SHARE_FOLDER_HELPER.AddSharedFolder(shareName);
}

void HandleUnmountSharedFolder(
    RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    Guest::protobuf::GuestAgent::String parameters;
    service.ParseProto(parameters, call);
    std::string shareName = parameters.value();
    if (shareName == DFX_SHARE_NAME) {
        return;
    }
    SHARE_FOLDER_HELPER.RemoveSharedFolder(shareName);
}

void HandleGetAvailableLetterCount(
    RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    auto count = service.GetAvailableLetterCount();
    LOG_INFO("Available driver count:{}", count);
    Guest::protobuf::GuestAgent::Integer result;
    result.set_value(count);
    COMMON::LinkBase::SerializeAndResponse(result, res);
}

void HandleShareFolderServiceIsReady(RecvFromHost &service, link::Call &call, link::Result &res)
{
    auto isViofsReady = GuestUtils::GetServiceState("VirtioFsDrv") == SERVICE_RUNNING;
    auto isHwfsReady = GuestUtils::GetServiceState("hwfs") == SERVICE_RUNNING;

    LOG_INFO("virtiofs state: {}", (isViofsReady ? "running" : "not started"));
    LOG_INFO("hwfs state: {}", (isHwfsReady ? "running" : "not started"));
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value((isViofsReady && isHwfsReady));
    COMMON::LinkBase::SerializeAndResponse(result, res);
}

#ifdef _FUZZ
void HandleStartFuzz(RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    LOG_INFO("receive msg -> StartFuzz guest");
    service.StartFuzz();
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value(true);
    COMMON::LinkBase::SerializeAndResponse(result, res);
}
#endif

void HandleIsWinLogon(RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    LOG_INFO("Check IsWinLogon");
    Guest::protobuf::GuestAgent::String parameters;
    service.ParseProto(parameters, call);
    bool ret = service.IsWinLogon();
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value(ret);
    COMMON::LinkBase::SerializeAndResponse(result, res);
}

bool RecvFromHost::IsWinLogon()
{
    if (SessionUtils::IsUserLogon()) {
        return true;
    }
    return false;
}

void UnmountCDRom()
{
    LOG_INFO("unmount UNATTEND CD-ROM");
    std::string delcdRomcmd = "powershell.exe -command "
        "\"echo %date% %time%; $device=Get-WmiObject Win32_PnpSignedDriver"
        "|where-Object{$_.DeviceName -like '*CD-ROM*' -and $_.DeviceId -like '*UNATTEND*'}"
        "|select-Object -First 1;PnpUtil /remove-device $device.DeviceId;\""
        " >>C:\\ProgramData\\VMAgent\\log\\update.log";
    if (!GuestUtils::ExecCmd(delcdRomcmd, false)) {
        LOG_ERR("unmount CD-ROM failed");
    }
    std::shared_ptr<WINCONTROL::SendToHost> sendtoHost = GUEST_MANAGER.GetSendToHost();
    if (sendtoHost != nullptr && SessionUtils::IsUserLogon()) {
        sendtoHost->UnmountUnattend();
    }
}

void ClearUpdateTemp()
{
    LOG_INFO("rmdir UpdateTemp");
    std::string psCmd = "cmd /q /C \""
    "rd /s /q %ProgramData%\\VMAgent\\UpdateTemp >>C:\\ProgramData\\VMAgent\\log\\update.log\"";
    if (!GuestUtils::ExecCmd(psCmd, false)) {
        LOG_ERR("rmdir UpdateTemp failed");
    };
}

void Reboot()
{
    LOG_INFO("reboot");
    std::string restartCmd = "shutdown -r -t 0";
    if (!GuestUtils::ExecCmd(restartCmd, false)) {
        LOG_ERR("Failed to execute {}", restartCmd);
    }
}

//清理弹窗
void RemovePop()
{
    LOG_INFO("stop update_confirm");
    GuestUtils::ExecCmd("cmd /q /C \"taskkill /F /IM update_confirm.exe\"", false);
    LOG_INFO("stop updateBar");
    GuestUtils::ExecCmd("cmd /q /C \"taskkill /F /IM update_bar.exe\"", false);
    LOG_INFO("delete update_bar.exe");
    GuestUtils::ExecCmd("cmd /q /C \"del /F /Q C:\\ProgramData\\VMAgent\\update_bar.exe\"", false);
    LOG_INFO("delete update_confirm.exe");
    GuestUtils::ExecCmd("cmd /q /C \"del /F /Q C:\\ProgramData\\VMAgent\\update_confirm.exe\"", false);
}

void HandleUpdate(RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    LOG_INFO("Update file");
    WDDM_UPDATE = false;
    Guest::protobuf::GuestAgent::UpdateInfo parameters;
    service.ParseProto(parameters, call);
    std::string fileName = parameters.filename();
    std::string fileHash = parameters.filehash();
    LOG_INFO("Update file:{}", fileName);
    bool updateResult;
    if (!TextUtils::IsValidFileName(fileName)) {
        LOG_ERR("Invalid filename");
        updateResult = false;
    } else {
        updateResult = service.UpdateFile(service, fileName, fileHash);
    }
    LOG_INFO("Update result:{}", updateResult);
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value(updateResult);
    COMMON::LinkBase::SerializeAndResponse(result, res);
    LOG_INFO("clear UpdateTemp");
    if (updateResult) {
        if (WDDM_UPDATE) {
            LOG_INFO("update succes, restart...");
            Reboot();
        } else {
            ClearUpdateTemp();
            if (DRIVER_UPDATING) {
                RemovePop();
                DRIVER_UPDATING = false;
                LOG_INFO("update succes, restart...");
                Reboot();
            } else {
                UnmountCDRom();
            }
        }
    }
}

void HandleNotifyUpToDate(RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    LOG_INFO("NotifyUpToDate");
    service.UpdateCallback();
    PERF_EVENT_DISPATCHER.CheckUserLogon();
    UnmountCDRom();
    if (TextUtils::FileExists("C:\\ProgramData\\VMAgent\\wddm\\svgampwddm.inf")) {
        ClearUpdateTemp();
        LOG_INFO("move wddm to driver1");
        GuestUtils::ExecCmd("cmd /q /C \"move /Y C:\\ProgramData\\VMAgent\\wddm C:\\ProgramData\\VMAgent\\driver1\\\"", false);
    }
    if (SessionUtils::IsUserLogon()) {
        DRIVER_REPORT.ReportData();
    }
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value(true);
    COMMON::LinkBase::SerializeAndResponse(result, res);
}

bool QueryUpdateConfirm()
{
    LOG_INFO("copy confirm file");
    if (!GuestUtils::IsProcessRunning("update_confirm.exe") && !GuestUtils::IsProcessRunning("update_bar.exe")) {
        if (!TextUtils::Cmds2File(UPDATE_CONFIRM_BAT, UPDATE_CONFIRM_PATH)) {
            LOG_ERR("Failed to generate {}", UPDATE_CONFIRM_PATH);
            return false;
        }
        if (!GuestUtils::ExecCmd(UPDATE_CONFIRM_PATH + " 1>>C:\\ProgramData\\VMAgent\\log\\update.log 2>&1", false)) {
            LOG_ERR("Failed to execute {}", UPDATE_CONFIRM_PATH, false);
            return false;
        }
        LOG_INFO("show update_confirm to choose");
        std::string updateCmd = "C:\\ProgramData\\VMAgent\\update_confirm.exe";
        int select = GuestUtils::ExecCmdResult(updateCmd, true);
        if (select == 1) {
            LOG_INFO("choose Yes.show update_bar");
            GuestUtils::ExecCmd("C:\\ProgramData\\VMAgent\\update_bar.exe", true, false);
            return true;
        } else {
            if (select == 0) {
                LOG_INFO("user cancel update");
            } else {
                LOG_INFO("user no operation or something");
                RemovePop();
            }
            UnmountCDRom();
            return false;
        }
    }
    return false;
}

void ExeVmagentUpdate(const std::string &batPath)
{
    LOG_INFO("exe VMAgent updateBat");
    if (!GuestUtils::ExecCmd("cmd /q /C \"call " + batPath
        + " 1>>C:\\ProgramData\\VMAgent\\log\\update.log 2>&1\"", false)) {
        LOG_ERR("Failed to execute {}", batPath, false);
    }
    int count = 0;
    while (TextUtils::FileExists(batPath) && count < POLLING_COUNT) {
        LOG_INFO("retry to execute {}", batPath);
        Sleep(POLLING_TIME);
        GuestUtils::ExecCmd("cmd /q /C \"call " + batPath
        + " 1>>C:\\ProgramData\\VMAgent\\log\\update.log 2>&1\"", false);
        count++;
    }
    LOG_INFO("Update VMAgent success");
}

bool UpdateWddm()
{
    LOG_INFO("Start update wddm");
    RemovePop();
    WDDM_UPDATE = true;
    const std::vector<std::string> cmds = cmdMap.find("wddm")->second;
    const std::string batPath = batPathMap.find("wddm")->second;
    LOG_INFO("generate file wddmUpdate.bat");
    if (!TextUtils::Cmds2File(cmds, batPath)) {
        LOG_ERR("failed to generate {}", batPath);
        return false;
    }
    if (!GuestUtils::ExecCmd(batPath + " 1>>C:\\ProgramData\\VMAgent\\log\\update.log 2>&1", false)) {
        LOG_ERR("Failed to execute {}", batPath, false);
        return false;
    }
    LOG_INFO("Update wddm success");
    return true;
}

void PowercfgOff()
{
    LOG_INFO("Driver is Updating, close QuickStart");
    std::string disableQuickStartCmd = "powercfg /h off";
    if (!GuestUtils::ExecCmd(disableQuickStartCmd, false)) {
        LOG_ERR("Failed to disable quick start");
    }
}

void UpdateDriver(const std::string &batPath)
{
    if (!QueryUpdateConfirm()) {
        RemovePop();
        return;
    }
    DRIVER_UPDATING = true;
    PowercfgOff();
    if (!GuestUtils::ExecCmd(batPath + " 1>>C:\\ProgramData\\VMAgent\\log\\update.log 2>&1", false)) {
        LOG_ERR("Failed to execute {}", batPath, false);
        RemovePop();
        return;
    }
    LOG_INFO("Start remove repeat old Driver");
    if (!TextUtils::Cmds2File(DRIVER_DELETE_REPEAT, DRIVER_DELETE_REPEAT_PATH)) {
        LOG_ERR("failed to generate {}", DRIVER_DELETE_REPEAT_PATH);
    }
    if (!GuestUtils::ExecCmd(DRIVER_DELETE_REPEAT_PATH +
        " 1>>C:\\ProgramData\\VMAgent\\log\\update.log 2>&1", false)) {
        LOG_ERR("Failed to execute {}", DRIVER_DELETE_REPEAT_PATH, false);
    }
    LOG_INFO("Start update driver wddm");
    std::string temp = TEMP_DIR;
    if (GuestUtils::IsDirEmpty(temp)) {
        RemovePop();
        return;
    }
    std::string currfile = CURR_DIR + "VMAgent\\driver1\\wddm\\svgampwddm.inf";
    std::string tempfile = TEMP_DIR + "\\wddm\\svgampwddm.inf";
    if (GuestUtils::CalcHash(currfile) == GuestUtils::CalcHash(tempfile)) {
        LOG_INFO("wddm is latest");
        std::string delcmd = "cmd /q /C \"rmdir /s /q " + TEMP_DIR + "\\wddm\\";
        if (!GuestUtils::ExecCmd(delcmd, false)) {
            LOG_ERR("Failed to delete wddm");
        }
        LOG_INFO("move driver.zip to VMAgent");
        if (!GuestUtils::ExecCmd("cmd /q /C \""
            "move /Y C:\\ProgramData\\VMAgent\\UpdateTemp\\driver.zip C:\\ProgramData\\VMAgent\\ "
            "1>>C:\\ProgramData\\VMAgent\\log\\update.log 2>&1\"", false)) {
            LOG_ERR("Failed to execute move driver.zip", false);
            return;
        }
        LOG_INFO("Update Driver success");
        return;
    }
    if (UpdateWddm()) {
        LOG_INFO("Update Driver success");
    }
}

void FileLatestHandle(const std::string &fileTag, const std::string file2)
{
    LOG_INFO("{} is latest", fileTag);
    std::string delcmd = "cmd /q /C \"del /f /q " + file2 +"\"";
    if (!GuestUtils::ExecCmd(delcmd, false)) {
        LOG_ERR("Failed to delete {}", fileTag);
    }
    if (fileTag == "Driver" && SessionUtils::IsUserLogon()) {
        DRIVER_REPORT.ReportData();
    }
}

void Update(const std::string &fileTag, const std::string &dir, const std::string &fileName)
{
    if (!TextUtils::IsValidFileName(fileName)) {
        LOG_ERR("Invalid filename");
        return;
    }
    std::string file1 = CURR_DIR + dir + "\\" + fileName;
    std::string file2 = TEMP_DIR + fileName;
    std::string temp = TEMP_DIR;
    if (GuestUtils::CalcHash(file1) == GuestUtils::CalcHash(file2)) {
        FileLatestHandle(fileTag, file2);
        return;
    }
    LOG_INFO("Start update {}", fileTag);
    if (GuestUtils::IsDirEmpty(temp) || GuestUtils::CalcHash(file2).empty()) {
        LOG_INFO("{} can not update,new file not exist", fileTag);
        return;
    }
    const std::vector<std::string> cmds = cmdMap.find(fileTag)->second;
    const std::string batPath = batPathMap.find(fileTag)->second;
    LOG_INFO("generate file {}Update.bat", fileTag);
    if (!TextUtils::Cmds2File(cmds, batPath)) {
        LOG_ERR("failed to generate {}", batPath);
        return;
    }
    if (fileTag == "VMAgent") {
        LOG_INFO("move UpdateTemp\\agent_service.exe to agent_service1.exe", false);
        if (!GuestUtils::ExecCmd("cmd /q /C \""
            "move /Y %PROGRAMDATA%\\VMAgent\\UpdateTemp\\agent_service.exe %PROGRAMDATA%\\VMAgent\\agent_service1.exe "
            "1>>C:\\ProgramData\\VMAgent\\log\\update.log 2>&1\"", false)) {
            LOG_ERR("Failed to execute move agent_service.exe", false);
            return;
        }
        std::thread t1(ExeVmagentUpdate, batPath);
        t1.detach();
    } else if (fileTag == "Driver") {
        UpdateDriver(batPath);
    } else {
        if (!GuestUtils::ExecCmd(batPath + " 1>>C:\\ProgramData\\VMAgent\\log\\update.log 2>&1", false)) {
            LOG_ERR("Failed to execute {}", batPath, false);
            return;
        }
        LOG_INFO("Update {} success", fileTag);
    }
    if (fileTag == "Config") {
        // 更新应用时长白名单
        PROCESSDETECT.Run();
    }
}

void UpdatePerformanceFiles(RecvFromHost &service)
{
    Update("ApplicationWindowHelper", "performance", "application_window_helper.exe");
    Update("PreProcessWndcontrol", "performance", "pre_process_wndcontrol.exe");
    Update("PsHideWindow", "performance", "ps_hide_window.dll");
    Update("PsProcessControl", "performance", "ps_process_control.exe");
    Update("WndFetch", "performance", "wndtext_fetch_helper.exe");
    Update("PsMon", "performance", "process_monitor.dll");
    Update("InstallConf", "VMAgent\\config", "installationList.json");
    Update("VisualEffectsEdit", "performance", "VisualEffectsEdit.exe");
    Update("PreloadHelper", "performance", "PreloadHelper.exe");
    Update("PerfCfg", "performance", "perf.cfg");
    Update("AutoPauseConfig", "VMAgent\\config", "AutoPauseList.json");
    service.UpdateCallback();
}

void UpdateAppFilterFiles()
{
    APP_FILTER_MANAGER.StopAll();
    Update("AppFilter", "AppFilter", "config.json");
    Update("AppFilter", "AppFilter", "FilterAgent.exe");
    APP_FILTER_MANAGER.Start();
}

void QueryUpdateFile()
{
    LOG_INFO("QueryUpdateFile-generate file GetFile.bat");
    if (!TextUtils::Cmds2File(GET_DRIVER_AGENT_FILE, GET_DRIVER_AGENT_PATH)) {
        LOG_ERR("Failed to generate {}", GET_DRIVER_AGENT_PATH);
    }
    if (!GuestUtils::ExecCmd("cmd /q /C \"call " + GET_DRIVER_AGENT_PATH
        + " 1>>C:\\ProgramData\\VMAgent\\log\\update.log 2>&1\"", false)) {
        LOG_ERR("Failed to execute {}", GET_DRIVER_AGENT_PATH, false);
    }
    int count = 0;
    while (TextUtils::FileExists(GET_DRIVER_AGENT_PATH) && count < POLLING_COUNT) {
        LOG_ERR("retry to execute {}", GET_DRIVER_AGENT_PATH);
        Sleep(POLLING_TIME);
        GuestUtils::ExecCmd("cmd /q /C \"call " + GET_DRIVER_AGENT_PATH
        + " 1>>C:\\ProgramData\\VMAgent\\log\\update.log 2>&1\"", false);
        count++;
    }
}

bool RecvFromHost::UpdateFile(RecvFromHost &service, const std::string &fileName, const std::string &fileHash)
{
    LOG_DEBUG("Start update {}", fileName);
    if (!TextUtils::IsValidFileName(fileName)) {
        LOG_ERR("Invalid filename");
        return false;
    }
    std::string setFulldump = "cmd /q /C \"reg add HKLM\\SYSTEM\\CurrentControlSet\\Control\\CrashControl "
        "/v CrashDumpEnabled /t REG_DWORD /d 1 /f \"";
    if (!GuestUtils::ExecCmd(setFulldump, false)) {
        LOG_ERR("Failed to setfulldump");
    }
    QueryUpdateFile();
    std::string file1 = CURR_DIR + "VMAgent\\agent_service.exe";
    std::string file2 = TEMP_DIR + "agent_service.exe";
    std::string temp = TEMP_DIR;
    if (_access(temp.c_str(), 0) !=0 || GuestUtils::IsDirEmpty(temp) || GuestUtils::CalcHash(file2).empty()) {
        LOG_ERR("Invalid update file");
        return false;
    }
    if (!GuestUtils::IsDirEmpty(temp) && !GuestUtils::CalcHash(file2).empty() &&
        GuestUtils::CalcHash(file1) != GuestUtils::CalcHash(file2)) {
        Update("VMAgent", "VMAgent", "agent_service.exe");
        return false;
    } else {
        LOG_INFO("agent_service.exe is latest");
        std::string delcmd = "cmd /q /C \"del /f /q " + file2 +"\"";
        if (!GuestUtils::ExecCmd(delcmd, false)) {
            LOG_ERR("Failed to delete agent_service.exe");
        }
    }
    Update("Config", "VMAgent\\config", "PerfSoftwareList.json");
    Update("WinEvtMonitor", "WinEvtMonitor", "win_evt_monitor.exe");
    Update("SVGA_ADAPTER", "display", "svga_adapter.dll");
    Update("Display", "display", "display.exe");
    UpdateAppFilterFiles();
    UpdatePerformanceFiles(service);
    Update("Driver", "VMAgent", "driver.zip");
    return GuestUtils::IsDirEmpty(temp);
}

void RecvFromHost::UpdateCallback()
{
    PROCESS_MONITOR_INJECTOR.DetectAndInject();
    if (PERF_MANAGER.Init()) {
        LOG_ERR("Performance manager init failed");
    }
}

bool RecvFromHost::NetConfig(const std::string &ipAddress, const std::string &gatewayIp)
{
    LOG_INFO("Start net config");
    if (!TextUtils::CheckIpAddr(ipAddress)) {
        LOG_ERR("Invalid ip address");
        return false;
    }
    if (gatewayIp != "default" && !TextUtils::CheckIpAddr(gatewayIp)) {
        LOG_ERR("Invalid gateway ip address");
        return false;
    }

    std::string ip = ipAddress;
    if (gatewayIp == "default") {
        m_gateway = ip.substr(0, ip.rfind(".")) + ".1";
    } else {
        m_gateway = gatewayIp;
    }

    if (!GuestUtils::SetNetCard(ip, m_gateway, autoSyncDnsEnabled)) {
        LOG_ERR("Set netcard failed");
        return false;
    }
    LOG_INFO("net set complete");
    return true;
}

bool RecvFromHost::CorrectTime(const std::string &hostTime, int timeZoneOffset)
{
    LOG_INFO("Start corrcet VM time {}, and correct timezone {}", hostTime, timeZoneOffset);
    SYSTEMTIME systemTime;
    int ret = sscanf_s(hostTime.c_str(), "%d-%d-%d %d:%d:%d", &systemTime.wYear, &systemTime.wMonth, &systemTime.wDay,
        &systemTime.wHour, &systemTime.wMinute, &systemTime.wSecond);
    if (ret != TIME_ARGUMENT_COUNT) {
        LOG_ERR("fail to scanf time, result is:{}", ret);
        return false;
    }
    if (!GuestUtils::SetVmTimeZone(timeZoneOffset)) {
        LOG_ERR("vm time zone set failed");
        return false;
    }
    if (!GuestUtils::SetVmTime(systemTime)) {
        LOG_ERR("vm time set failed");
        return false;
    }
    return true;
}

void RecvFromHost::SetOsType(const std::string &osType)
{
    LOG_INFO("Host os is {}", osType);
    m_hostos = osType;
}

int RecvFromHost::GetAvailableLetterCount()
{
    return  GuestUtils::GetAvailableLetterCount();
}

void RecvFromHost::SetAutoSyncDnsEnabled(bool enabled)
{
    autoSyncDnsEnabled = enabled;
}

void RecvFromHost::SetForceShutdownState(bool state)
{
    forceShutdownState = state;
}

bool RecvFromHost::GetForceShutdownState()
{
    return forceShutdownState;
}

bool RecvFromHost::GetDriverUpdateState()
{
    return DRIVER_UPDATING;
}

void HandleCopyAndPasteActionStatus(RecvFromHost& service, Guest::protobuf::link::Call& call,
    Guest::protobuf::link::Result& res)
{
    LOG_INFO("Start catch file copy and paste actions!");
    SysCpuCalc::GetInstance().CollectProcLoad();
    bool ret = SysCpuCalc::GetInstance().FilterFileCopyAndPasteActions();
    LOG_INFO("Get file copy and paste actions result {}.", ret);
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value(ret);
    COMMON::LinkBase::SerializeAndResponse(result, res);
}

void HandleCompressDecompressActionStatus(RecvFromHost& service, Guest::protobuf::link::Call& call,
    Guest::protobuf::link::Result& res)
{
    LOG_INFO("Start catch compress and decompress actions!");
    SysCpuCalc::GetInstance().CollectProcLoad();
    bool ret = SysCpuCalc::GetInstance().FilterCompressDecompressActions();
    LOG_INFO("Get compress and decompress action result {}.", ret);
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value(ret);
    COMMON::LinkBase::SerializeAndResponse(result, res);
}

void HandleApplicationWindowStatus(RecvFromHost& service, Guest::protobuf::link::Call& call,
    Guest::protobuf::link::Result& res)
{
    LOG_INFO("start detect is running application in white list.");
    bool ret = APPLICATION_MONITOR.IsRunningApplicationInWhiteList();
    LOG_INFO("start get running application in white list result {}.", ret);
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value(ret);
    COMMON::LinkBase::SerializeAndResponse(result, res);
}

void HandleSetTouchKeyboardVisibility(RecvFromHost &service, Guest::protobuf::link::Call &call,
    Guest::protobuf::link::Result &res)
{
    LOG_INFO("SetTouchKeyboardVisibility");
    Guest::protobuf::GuestAgent::Bool parameters;
    service.ParseProto(parameters, call);
    bool visibility = parameters.value();
    LOG_INFO("start get touck keyboard visibility result {}.", visibility);
    HKEY hkcu = HKEY_USERS;
    std::string subKey = PERF_UTILS.GetCurrentUserSid() + TOUCH_KEYBOARD_REG_SUBKEY_PATH;
    RegistryUtilsEx registryModifier(hkcu, subKey);
    DWORD visibilityVal = visibility ? 1 : 0;
    LONG ret = registryModifier.RegSetDword("TipbandDesiredVisibility", visibilityVal);
    if (ret != ERROR_SUCCESS) {
        LOG_ERR("RegSetDword failed. {}", registryModifier.ToErrorString(ret));
    }
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value(ret == ERROR_SUCCESS);
    COMMON::LinkBase::SerializeAndResponse(result, res);
}

void HandleSyncHostDomainAccountAndSN(RecvFromHost &service, Guest::protobuf::link::Call &call,
    Guest::protobuf::link::Result &res)
{
    LOG_INFO("Set domain account name and sn");
    Guest::protobuf::GuestAgent::HostIdentityInfo parameters;
    service.ParseProto(parameters, call);
    GuestUtils::SetHostDomainAccountAndSN(parameters.domainaccountname(), parameters.sn());
}

void HandleSetAutoSyncDnsEnabled(RecvFromHost &service, Guest::protobuf::link::Call &call,
    Guest::protobuf::link::Result &res)
{
    Guest::protobuf::GuestAgent::Bool parameters;
    service.ParseProto(parameters, call);
    LOG_INFO("Set auto sync dns enabled = {}", parameters.value());
    service.SetAutoSyncDnsEnabled(parameters.value());
}

void HandleSyncProxy(RecvFromHost &service, link::Call &call, link::Result &res)
{
    LOG_INFO("Set proxy");
    Guest::protobuf::GuestAgent::ProxyInfo parameters;
    service.ParseProto(parameters, call);
    std::string server = parameters.server();
    std::string exclusions = parameters.exclusions();
    bool ret = GuestUtils::SetProxy(server, exclusions);
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value(ret);
    COMMON::LinkBase::SerializeAndResponse(result, res);
}

void HandleSyncDNS(RecvFromHost &service, link::Call &call, link::Result &res)
{
    LOG_INFO("Set dns");
    Guest::protobuf::GuestAgent::DNSInfo parameters;
    service.ParseProto(parameters, call);
    std::string primaryDNS = parameters.primarydns();
    std::string secondaryDNS = parameters.secondarydns();
    bool ret = GuestUtils::SetDNS(primaryDNS, secondaryDNS);
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value(ret);
    COMMON::LinkBase::SerializeAndResponse(result, res);
}

void HandleCheckWinUpdate(RecvFromHost &service, link::Call &call, link::Result &res)
{
    LOG_INFO("Check win is updating");
    bool ret = WinUpdateUtils::CheckWinUpdating();
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value(ret);
    COMMON::LinkBase::SerializeAndResponse(result, res);
}

void HandleServiceAlive(RecvFromHost &service, link::Call &call, link::Result &res)
{
    LOG_INFO("AgentServiceAlive");
    Guest::protobuf::GuestAgent::Bool result;
    result.set_value(true);
    COMMON::LinkBase::SerializeAndResponse(result, res);
}

void HandleTriggerVmUpdate(RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    LOG_INFO("Trigger vm update.");
    std::string shutdownCmd = "shutdown -s -t 0";
    if (!GuestUtils::ExecCmd(shutdownCmd, false, false)) {
        LOG_ERR("Failed to execute {}", shutdownCmd);
    }
}

void HandleInstallConfig(RecvFromHost &service, Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res)
{
    LOG_INFO("SetEdgeHomePage begin");
    std:string ntpStr = ",\"ntp\":{\"background_image\":{\"provider\":\"NoBackground\",\"userSelected\":true},"
        "\"background_image_type\":\"off\",\"hide_default_top_sites\":true,\"layout_mode\":3,\"news_feed_display\":"
        "\"off\",\"num_personal_suggestions\":0,\"quick_links_options\":0,\"record_user_choices\":[{\"setting\":"
        "\"recommended_sites\",\"source\":\"ntp\",\"value\":0}],\"show_greeting\":true,\"show_image_of_day\":false}}";
    HANDLE hUserToken = NULL;
    if (PERF_UTILS.GetUserToken(&hUserToken)) {
        std::string appDataLocal = COMMON::PATHUTILS::GetUserAppDataLocalFolder(hUserToken);
        CloseHandle(hUserToken);
        std::string path = appDataLocal + "\\Microsoft\\Edge\\User Data\\Default\\Preferences";
        TextUtils::ReplaceLastChar(path, ntpStr);
    }
    LOG_INFO("SetEdgeHomePage end");
}

#ifdef _FUZZ
int RecvFromHost::StartFuzz()
{
    TEST::GuestLinkFuzzWindowsServer::Init();
    LOG_INFO("StartFuzz");
    this->isFuzzMode = true;
    return 0;
}
#endif

}  // namespace GUEST
